package com.dlc.shop.allinpay.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dlc.shop.allinpay.OpenClient;
import com.dlc.shop.allinpay.config.AllinpayConfig;
import com.dlc.shop.allinpay.service.AllinpayMemberService;
import com.dlc.shop.allinpay.service.AllinpayOrderService;
import com.dlc.shop.allinpay.service.AllinpayService;
import com.dlc.shop.bean.dto.allinpay.*;
import com.dlc.shop.common.allinpay.constant.AllinpayConstant;
import com.dlc.shop.common.allinpay.constant.AllinpayPlatformAccountSet;
import com.dlc.shop.common.allinpay.member.constant.*;
import com.dlc.shop.common.allinpay.member.req.*;
import com.dlc.shop.common.allinpay.member.resp.*;
import com.dlc.shop.common.allinpay.order.req.*;
import com.dlc.shop.common.allinpay.order.resp.*;
import com.dlc.shop.common.bean.Allinpay;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.IpHelper;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.service.SysConfigService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

/**
 * @author lanhai
 */
@Service
@AllArgsConstructor
public class AllinpayServiceImpl implements AllinpayService {

    private final AllinpayConfig allinpayConfig;

    private final AllinpayMemberService allinpayMemberService;
    private final AllinpayOrderService allinpayOrderService;
    private final SysConfigService sysConfigService;

    @Override
    public void createMember(String bizUserId, Integer sysType) {
        CreateMember createMember = new CreateMember(bizUserId);
        createMember.setSource(VisitSourceType.PC.value());
        allinpayMemberService.createMember(createMember);
    }

    @Override
    public UserInfo getUserInfo(String bizUserId) {
        GetMemberInfo getMemberInfo = new GetMemberInfo(bizUserId);
        UserInfo userInfo = allinpayMemberService.getMemberInfo(getMemberInfo);
        // 个人会员(身份证号解密)
        OpenClient client = allinpayConfig.getClient();
        String encryptStr = userInfo.getIdentityCardNo();
        userInfo.setIdentityCardNo(encryptStr == null ? null : client.decrypt(encryptStr));
        return userInfo;
    }

    @Override
    public void sendVerificationCode(String userId, VerificationCodeDTO verificationCodeDTO) {
        if (StrUtil.isBlank(userId)) {
            return;
        }
        SendVerificationCode svc = new SendVerificationCode(userId, verificationCodeDTO.getPhone());
        Integer type = verificationCodeDTO.getVerificationCodeType();
        if (type != null
                && VerificationCodeType.instance(type) != null) {
            svc.setVerificationCodeType(type);
        }
        allinpayMemberService.sendVerificationCode(svc);
    }

    @Override
    public void bindPhone(String userId, VerificationCodeDTO verificationCodeDTO) {
        BindPhone bindPhone = new BindPhone(
                userId,
                verificationCodeDTO.getPhone(),
                verificationCodeDTO.getVerificationCode()
        );
        allinpayMemberService.bindPhone(bindPhone);
    }

    @Override
    public void unbindPhone(String userId, VerificationCodeDTO verificationCodeDTO) {
        UnbindPhone unbindPhone = new UnbindPhone(
                userId,
                verificationCodeDTO.getPhone(),
                verificationCodeDTO.getVerificationCode()
        );
        PhoneVerificationResp phoneVerificationResp = allinpayMemberService.unbindPhone(unbindPhone);
        if (Objects.equals(Constant.ERROR, phoneVerificationResp.getResult())) {
            throw new YamiShopBindException("yami.allinpay.exception.unbindPhoneFail");
        }
    }

    @Override
    public String updatePhoneByPayPwd(String bizUserId, String backUrl, UpdatePhoneByPayPwdDTO updatePhoneByPayPwdDTO) {
        UpdatePhoneByPayPwd updatePhoneByPayPwd = new UpdatePhoneByPayPwd();
        BeanUtils.copyProperties(updatePhoneByPayPwdDTO, updatePhoneByPayPwd);
        updatePhoneByPayPwd.setBizUserId(bizUserId);
        updatePhoneByPayPwd.setBackUrl(backUrl);
        OpenClient client = allinpayConfig.getClient();
        updatePhoneByPayPwd.setIdentityNo(client.encrypt(updatePhoneByPayPwd.getIdentityNo()));
        if (updatePhoneByPayPwd.getJumpPageType() == null) {
            updatePhoneByPayPwd.setJumpPageType(PageType.H5.value());
        }
        return allinpayMemberService.updatePhoneByPayPwd(updatePhoneByPayPwd);
    }

    @Override
    public void setRealName(String bizUserId, SetRealNameDTO setRealNameDTO) {
        OpenClient client = allinpayConfig.getClient();
        SetRealName setRealName = new SetRealName(
                bizUserId,
                setRealNameDTO.getName(),
                client.encrypt(setRealNameDTO.getIdentityNo())
        );
        allinpayMemberService.setRealName(setRealName);
    }

    @Override
    public void lockMember(LockMemberDTO lockMemberDTO) {
        LockMember lockMember = new LockMember(String.valueOf(lockMemberDTO.getUserId()));
        allinpayMemberService.lockMember(lockMember);
    }

    @Override
    public void unlockMember(LockMemberDTO lockMemberDTO) {
        UnlockMember unlockMember = new UnlockMember(String.valueOf(lockMemberDTO.getUserId()));
        allinpayMemberService.unlockMember(unlockMember);
    }

    @Override
    public CardBinInfo getBankCardBin(String cardNo) {
        GetBankCardBin getBankCardBin = new GetBankCardBin();
        OpenClient client = allinpayConfig.getClient();
        getBankCardBin.setCardNo(client.encrypt(cardNo));
        return allinpayMemberService.getBankCardBin(getBankCardBin);
    }

    @Override
    public ApplyBindBankCardResp applyBindBankCard(String userId, ApplyBankCardDTO applyBankCardDTO) {
        OpenClient client = allinpayConfig.getClient();
        ApplyBindBankCard applyBindBankCard = new ApplyBindBankCard();
        BeanUtils.copyProperties(applyBankCardDTO, applyBindBankCard);
        applyBindBankCard.setIdentityType(IdentityType.ID_CARD.value());
        applyBindBankCard.setBizUserId(userId);
        applyBindBankCard.setIdentityNo(client.encrypt(applyBankCardDTO.getIdentityNo()));
        applyBindBankCard.setCardNo(client.encrypt(applyBankCardDTO.getCardNo()));
        return allinpayMemberService.applyBindBankCard(applyBindBankCard);
    }

    @Override
    public void bindBankCard(String userId, BindBankCardDTO bindBankCardDTO) {
        BindBankCard bindBankCard = new BindBankCard();
        BeanUtils.copyProperties(bindBankCardDTO, bindBankCard);
        bindBankCard.setBizUserId(userId);
        allinpayMemberService.bindBankCard(bindBankCard);
    }

    @Override
    public void unbindBankCard(String userId, UnbindBankCardDTO unbindBankCardDTO) {
        OpenClient client = allinpayConfig.getClient();
        UnbindBankCard unbindBankCard = new UnbindBankCard();
        unbindBankCard.setBizUserId(userId);
        unbindBankCard.setCardNo(client.encrypt(unbindBankCardDTO.getCardNo()));
        allinpayMemberService.unbindBankCard(unbindBankCard);
    }

    @Override
    public List<BindCard> queryBankCard(String bizUserId, String cardNo) {
        QueryBankCard queryBankCard = new QueryBankCard(bizUserId);
        if (!ObjectUtils.isEmpty(cardNo)) {
            OpenClient client = allinpayConfig.getClient();
            queryBankCard.setCardNo(client.encrypt(cardNo));
        }
        return allinpayMemberService.queryBankCard(queryBankCard);
    }

    @Override
    public void applyBindAcct(String bizUserId, ApplyBindAcctDTO applyBindAcctDTO) {
        ApplyBindAcct applyBindAcct = new ApplyBindAcct();
        if (PayAcctType.instance(applyBindAcctDTO.getAcctType()) == null) {
            throw new YamiShopBindException("yami.allinpay.exception.acctError");
        }
        applyBindAcct.setBizUserId(bizUserId);
        applyBindAcct.setAcctType(applyBindAcctDTO.getAcctType());
        applyBindAcct.setAcct(applyBindAcctDTO.getAcct());
        Result result = allinpayMemberService.applyBindAcct(applyBindAcct);
        if (Objects.equals(result.getResult(), Constant.ERROR)) {
            throw new YamiShopBindException("yami.allinpay.exception.acctBindFail");
        }
    }

    @Override
    public QueryBindAcctResp queryBindAcct(String bizUserId) {
        ApplyBindAcct applyBindAcct = new ApplyBindAcct();
        applyBindAcct.setBizUserId(bizUserId);
        applyBindAcct.setOperationType("query");
        return allinpayMemberService.queryBindAcct(applyBindAcct);
    }

    @Override
    public String setPayPwd(String bizUserId, String backUrl, SetPayPwdDTO setPayPwdDTO) {
        OpenClient client = allinpayConfig.getClient();
        SetPayPwd setPayPwd = new SetPayPwd();
        BeanUtils.copyProperties(setPayPwdDTO, setPayPwd);
        setPayPwd.setBizUserId(bizUserId);
        setPayPwd.setIdentityType(IdentityType.ID_CARD.value());
        setPayPwd.setIdentityNo(client.encrypt(setPayPwdDTO.getIdentityNo()));
        setPayPwd.setBackUrl(backUrl);
        return allinpayMemberService.setPayPwd(setPayPwd);
    }

    @Override
    public String updatePayPwd(String bizUserId, String backUrl, SetPayPwdDTO setPayPwdDTO) {
        OpenClient client = allinpayConfig.getClient();
        UpdatePayPwd updatePayPwd = new UpdatePayPwd();
        BeanUtils.copyProperties(setPayPwdDTO, updatePayPwd);
        updatePayPwd.setBizUserId(bizUserId);
        updatePayPwd.setIdentityType(IdentityType.ID_CARD.value());
        updatePayPwd.setIdentityNo(client.encrypt(setPayPwdDTO.getIdentityNo()));
        updatePayPwd.setBackUrl(backUrl);
        return allinpayMemberService.updatePayPwd(updatePayPwd);
    }

    @Override
    public String resetPayPwd(String bizUserId, String backUrl, SetPayPwdDTO setPayPwdDTO) {
        OpenClient client = allinpayConfig.getClient();
        ResetPayPwd resetPayPwd = new ResetPayPwd();
        BeanUtils.copyProperties(setPayPwdDTO, resetPayPwd);
        resetPayPwd.setBizUserId(bizUserId);
        resetPayPwd.setIdentityType(IdentityType.ID_CARD.value());
        resetPayPwd.setIdentityNo(client.encrypt(setPayPwdDTO.getIdentityNo()));
        resetPayPwd.setBackUrl(backUrl);
        return allinpayMemberService.resetPayPwd(resetPayPwd);
    }

    @Override
    public String signAcctProtocol(String bizUserId, String backUrl, SignAcctProtocolDTO signAcctProtocolDTO) {
        SignAcctProtocol signAcctProtocol = new SignAcctProtocol();
        BeanUtils.copyProperties(signAcctProtocolDTO, signAcctProtocol);
        signAcctProtocol.setBizUserId(bizUserId);
        signAcctProtocol.setBackUrl(backUrl);
        signAcctProtocol.setSource(VisitSourceType.PC.value());
        return allinpayMemberService.signAcctProtocol(signAcctProtocol);
    }

    @Override
    public String signContractQuery(String bizUserId, SignAcctProtocolDTO signAcctProtocolDTO) {
        SignContractQuery signContractQuery = new SignContractQuery();
        BeanUtils.copyProperties(signAcctProtocolDTO, signContractQuery);
        signContractQuery.setBizUserId(bizUserId);
        signContractQuery.setSource(VisitSourceType.PC.value());
        return allinpayMemberService.signContractQuery(signContractQuery);
    }

    @Override
    public BankCardChangeBindPhoneResp bankCardChangeBindPhone(String bizUserId, BankCardChangeBindPhoneDTO bankCardChangeBindPhoneDTO) {
        BankCardChangeBindPhone bankCardChangeBindPhone = new BankCardChangeBindPhone();
        BeanUtils.copyProperties(bankCardChangeBindPhoneDTO, bankCardChangeBindPhone);
        bankCardChangeBindPhone.setBizUserId(bizUserId);
        bankCardChangeBindPhone.setIdentityType(IdentityType.ID_CARD.value());
        // 数据加密
        OpenClient client = allinpayConfig.getClient();
        bankCardChangeBindPhone.setCardNo(client.encrypt(bankCardChangeBindPhoneDTO.getCardNo()));
        bankCardChangeBindPhone.setIdentityNo(client.encrypt(bankCardChangeBindPhoneDTO.getIdentityNo()));
        if (!ObjectUtils.isEmpty(bankCardChangeBindPhoneDTO.getValidate())) {
            bankCardChangeBindPhone.setValidate(client.encrypt(bankCardChangeBindPhoneDTO.getValidate()));
        }
        if (!ObjectUtils.isEmpty(bankCardChangeBindPhoneDTO.getCvv2())) {
            bankCardChangeBindPhone.setCvv2(client.encrypt(bankCardChangeBindPhoneDTO.getCvv2()));
        }
        return allinpayMemberService.bankCardChangeBindPhone(bankCardChangeBindPhone);
    }

    @Override
    public void verifyBankCardChangeBindPhone(String bizUserId, VerifyBankCardChangeBindPhoneDTO verifyBankCardChangeBindPhoneDTO) {
        VerifyBankCardChangeBindPhone verifyBankCardChangeBindPhone = new VerifyBankCardChangeBindPhone();
        BeanUtils.copyProperties(verifyBankCardChangeBindPhoneDTO, verifyBankCardChangeBindPhone);
        verifyBankCardChangeBindPhone.setBizUserId(bizUserId);
        // 数据加密
        OpenClient client = allinpayConfig.getClient();
        if (!ObjectUtils.isEmpty(verifyBankCardChangeBindPhoneDTO.getValidate())) {
            verifyBankCardChangeBindPhone.setValidate(client.encrypt(verifyBankCardChangeBindPhoneDTO.getValidate()));
        }
        if (!ObjectUtils.isEmpty(verifyBankCardChangeBindPhoneDTO.getCvv2())) {
            verifyBankCardChangeBindPhone.setCvv2(client.encrypt(verifyBankCardChangeBindPhone.getCvv2()));
        }
        allinpayMemberService.verifyBankCardChangeBindPhone(verifyBankCardChangeBindPhone);
    }

    @Override
    public QueryBalanceResp queryBalance(String bizUserId, Integer sysType) {
        // 平台使用标准账户集，其余使用托管账户集
        String accountSetNo;
        if (Objects.equals(SysTypeEnum.PLATFORM.value(), sysType)) {
            accountSetNo = AllinpayPlatformAccountSet.STANDARD_BALANCE.value().toString();
        } else {
            Allinpay allinpay = sysConfigService.getSysConfigObject(Constant.ALLINPAY_CONFIG, Allinpay.class);
            accountSetNo = allinpay.getAccountSetNo();
        }
        QueryBalance queryBalance = new QueryBalance(bizUserId, accountSetNo);
        return allinpayOrderService.queryBalance(queryBalance);
    }

    @Override
    public IPage<InExpDetail> queryInExpDetail(String bizUserId, PageParam<InExpDetail> pageParam, QueryInExpDetailDTO queryInExpDetailDTO) {
        QueryInExpDetail queryInExpDetail = new QueryInExpDetail();
        BeanUtils.copyProperties(queryInExpDetailDTO, queryInExpDetail);
        queryInExpDetail.setBizUserId(bizUserId);
        // 计算分页
        queryInExpDetail.setQueryNum(Integer.parseInt(String.valueOf(pageParam.getSize())));
        queryInExpDetail.setStartPosition(Integer.parseInt(String.valueOf((1 + (pageParam.getCurrent() - 1) * pageParam.getSize()))));
        // 发送请求，并封装为分页展示类
        QueryInExpDetailResp resp = allinpayOrderService.queryInExpDetail(queryInExpDetail);
        IPage<InExpDetail> pageVO = new Page<>();
        pageVO.setTotal(resp.getTotalNum());
        pageVO.setRecords(resp.getInExpDetail());
        int pages = Integer.parseInt(String.valueOf(pageVO.getTotal() / pageParam.getSize()));
        pageVO.setPages(pageVO.getTotal() % pageParam.getSize() == 0 ? pages : pages + 1);
        return pageVO;
    }

    @Override
    public String payBySms(String bizUserId, PayBySmsDTO payBySmsDTO) {
        PayBySms payBySms = new PayBySms();
        BeanUtils.copyProperties(payBySmsDTO, payBySms);
        payBySms.setBizUserId(bizUserId);
        String ipAddr = IpHelper.getIpAddr();
        payBySms.setConsumerIp(ipAddr);
        return allinpayOrderService.payBySms(payBySms);
    }

    @Override
    public String payByPwd(String bizUserId, PayByPwdDTO payByPwdDTO) {
        PayByPwd payByPwd = new PayByPwd();
        BeanUtils.copyProperties(payByPwdDTO, payByPwd);
        payByPwd.setBizUserId(bizUserId);
        String ipAddr = IpHelper.getIpAddr();
        payByPwd.setConsumerIp(ipAddr);
        return allinpayOrderService.payByPwd(payByPwd);
    }

    @Override
    public PayByBackSmsResp payByBackSms(String bizUserId, PayByBackSmsDTO payByBackSmsDTO) {
        PayByBackSmsReq payByBackSmsReq = new PayByBackSmsReq();
        BeanUtils.copyProperties(payByBackSmsDTO, payByBackSmsReq);
        payByBackSmsReq.setBizUserId(bizUserId);
        String ipAddr = IpHelper.getIpAddr();
        payByBackSmsReq.setConsumerIp(ipAddr);
        return allinpayOrderService.payByBackSms(payByBackSmsReq);
    }

    @Override
    public ResendPaySmsResp resendPaySms(String bizOrderNo) {
        ResendPaySmsReq resendPaySmsReq = new ResendPaySmsReq();
        resendPaySmsReq.setBizOrderNo(bizOrderNo);
        return allinpayOrderService.resendPaySms(resendPaySmsReq);
    }

    @Override
    public GetOrderStatusResp getOrderStatus(String bizUserId, String bizOrderNo) {
        GetOrderStatusReq getOrderStatusReq = new GetOrderStatusReq();
        getOrderStatusReq.setBizUserId(bizUserId);
        getOrderStatusReq.setBizOrderNo(bizOrderNo);
        return allinpayOrderService.getOrderStatus(getOrderStatusReq);
    }

    @Override
    public String buildAliAppPayUrl(AliAppPayUrlDTO aliAppPayUrlDTO) {
        // 补充默认参数
        if (Objects.isNull(aliAppPayUrlDTO.getAppId())) {
            aliAppPayUrlDTO.setAppId(AllinpayConstant.ALI_DEFAULT_APP_ID);
        }
        if (Objects.isNull(aliAppPayUrlDTO.getPage())) {
            aliAppPayUrlDTO.setSchemeUrl(AllinpayConstant.ALI_DEFAULT_PAGE);
        }
        // 参数加密
        aliAppPayUrlDTO.setJson(URLEncoder.encode("payinfo=" + URLEncoder.encode(aliAppPayUrlDTO.getJson(), StandardCharsets.UTF_8), StandardCharsets.UTF_8));
        aliAppPayUrlDTO.setSchemeUrl(URLEncoder.encode(aliAppPayUrlDTO.getSchemeUrl(), StandardCharsets.UTF_8));
        // 补充模板参数
        return String.format(
                AllinpayConstant.ALI_APP_PAY_URL_TEMPLATE,
                aliAppPayUrlDTO.getAppId(),
                aliAppPayUrlDTO.getPage(),
                aliAppPayUrlDTO.getSchemeUrl(),
                aliAppPayUrlDTO.getJson()
        );
    }
}
